#include "form_login.h"
#include "ui_form_login.h"

// add necessary includes here
#include "utils/database/database_bll_t1c.h"
#include "utils/configure/configure_bll.h"
#include "utils/algorithm/algorithm_bll_t1c.h"
#include "utils/keyboard/keyboard_mgr.h"
#include "ui/share/qlineeditpwd.h"

#define DF_AUTO_LOGIN_TIMEOUT       3000


/*
 * Function:    FormLogin
 * Description: The default constructor
 * Paramer:     void
 * Return:
 */
FormLogin::FormLogin(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FormLogin)
{
    qDebug() << Q_FUNC_INFO;

    ui->setupUi(this);
}

/*
 * Function:    ~FormLogin
 * Description: The default destructor
 * Paramer:     void
 * Return:
 */
FormLogin::~FormLogin()
{
    qDebug() << Q_FUNC_INFO;

    delete ui;
}

/*
 * Function:    getInstance
 * Description: Get an instance of "FormLogin" class, if exist, return it
 * Paramer:     QWidget *pParent - the pointer of QWidget class
 * Return:      the pointer of "WidgetManager" class
 */
FormLogin* FormLogin::getInstance(QWidget *pParent)
{
    static FormLogin *pNew = NULL;
    if(!pNew) {
        qDebug() << Q_FUNC_INFO;

        // Create a new object if it doesn't exist
        pNew = new FormLogin(pParent);
        if(NULL == pNew) return NULL;

        // After constructing object, initialize the object
        pNew->_initialze();
    }
    else {
        // Set the parent object
        pNew->setParent(pParent);
    }

    // Initialize control's UI
    pNew->_initUi();

    return pNew;
}

/*
 * Function:    _initialze
 * Description: After constructing object, initialize the object
 * Paramer:     void
 * Return:      void
 */
void FormLogin::_initialze()
{
    qDebug() << Q_FUNC_INFO;

    if(!m_pTimerLogin) m_pTimerLogin = new QTimer();
    Q_ASSERT(NULL != m_pTimerLogin);

    if(!m_pLineEditPwd) m_pLineEditPwd = new QLineEditPwd(this);
    Q_ASSERT(NULL != m_pLineEditPwd);

    // Signal-slot initialization
    std::vector<bool> vecConnect;
    vecConnect.push_back(QObject::connect(this, SIGNAL(signalRefreshUI()), this, SLOT(slotRefreshUI()), Qt::QueuedConnection));
    vecConnect.push_back(QObject::connect(m_pTimerLogin, SIGNAL(timeout()), this, SLOT(slotAutoLoginTimeout())));

    for(int i=0; i<(int)vecConnect.size(); i++) {
        Q_ASSERT(vecConnect.at(i));
    }

    DatabaseBLL_T1C::getInstance(this);
}

/*
* Function:		_initUi
* Description:	Init the window style
* Paramer:		void
* Return:		void
*/
void FormLogin::_initUi()
{
    qDebug() << Q_FUNC_INFO;

    // Displays the background image of the window
    QWidget::setAttribute(Qt::WA_StyledBackground);

    ui->label_Vision->setVisible(false);
    ui->label_PromtInfo->setText("");
    ui->label_PromtInfo->setFixedHeight(20);
    ui->comboBox_User->setEditable(true);

    ui->horizontalLayout_User->setAlignment(Qt::AlignLeft);
    ui->horizontalLayout_Pwd->setAlignment(Qt::AlignLeft);
    ui->horizontalLayout_Confirm->setAlignment(Qt::AlignLeft);

    SET_STYLE_SHEET(QString(":/%1/home/%2.qss").arg("skin_1").arg(this->objectName()));

    ui->checkBox_RememberMe->setFocusPolicy(Qt::NoFocus);
    ui->checkBox_AutoLogin->setFocusPolicy(Qt::NoFocus);
    ui->comboBox_User->setView(new QListView());

    m_pLineEditPwd->setFixedSize(ui->comboBox_User->width(), ui->comboBox_User->height());
    ui->horizontalLayout_Pwd->addWidget(m_pLineEditPwd);
}

/*
* Function:		changeEvent
* Description:	Triggers an event before it is switch language
* Paramer:		QShowEvent *e - the pointer of "QEvent"
* Return:		void
*/
void FormLogin::changeEvent(QEvent *e)
{
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);

        qDebug() << Q_FUNC_INFO;
        break;
    default:
        break;
    }

    QWidget::changeEvent(e);
}

/*
* Function:		on_pushButton_Login_clicked
* Description:	Verify the user name and password to log in to the main screen
* Paramer:		void
* Return:		void
*/
void FormLogin::on_pushButton_Login_clicked()
{
    qDebug() << Q_FUNC_INFO;

    int nRetVal = 0;
    QString sUserName = ui->comboBox_User->currentText().trimmed();
    QString sUserPwd = m_pLineEditPwd->text().trimmed();

    if("" == sUserName) {
        ui->label_PromtInfo->setText(tr("User cannot be empty"));
    }
    else if("" == sUserPwd && DEF_ACCOUNT_GUEST != sUserName) {
        ui->label_PromtInfo->setText(tr("Password cannot be empty"));
    }
    else {
        // Verify user's password
        QString sPwdAES = AlgorithmBLL_T1C::getInstance(this)->encryptionAES(sUserPwd);
        nRetVal = DatabaseBLL_T1C::getInstance(this)->verifyUserPwd(sUserName, sPwdAES);
        if(0 != nRetVal) {
            ui->label_PromtInfo->setText(tr("password not match"));
        }
        else
        {
            // Disable auto login
            m_pTimerLogin->stop();

            // Save login option info
            _saveLoginOption();

            // The user logs in successfully and enters the main interface
            emit signalFinishLogin();
        }
    }

    // Display password error message
    QTimer::singleShot(3000, this, [=](){
        ui->label_PromtInfo->setText("");
        ui->checkBox_AutoLogin->setChecked(false);
    });

    qDebug() << Q_FUNC_INFO << sUserName << nRetVal;
}

/*
* Function:		on_comboBox_User_currentIndexChanged
* Description:	Verify the user name and password to log in to the main screen
* Paramer:		QString &arg1 - the user name
* Return:		void
*/
void FormLogin::on_comboBox_User_currentTextChanged(const QString &arg1)
{
    qDebug() << Q_FUNC_INFO << arg1;

    m_pLineEditPwd->setText("");
    ui->checkBox_RememberMe->setChecked(false);
    ui->checkBox_AutoLogin->setChecked(false);
}

/*
* Function:		on_checkBox_RememberMe_stateChanged
* Description:	Association remembers password and automatic login
* Paramer:		int arg1 - the check status
* Return:		void
*/
void FormLogin::on_checkBox_RememberMe_stateChanged(int arg1)
{
    qDebug() << Q_FUNC_INFO << arg1;

    if(0 == arg1) {
        ui->checkBox_AutoLogin->setChecked(false);
        ui->checkBox_AutoLogin->setDisabled(true);
    }
    else {
        ui->checkBox_AutoLogin->setChecked(true);
        ui->checkBox_AutoLogin->setDisabled(false);
    }
}

/*
* Function:		on_checkBox_AutoLogin_stateChanged
* Description:	If not checked, the automatic login will be cancelled
* Paramer:		int arg1 - the check status
* Return:		void
*/
void FormLogin::on_checkBox_AutoLogin_stateChanged(int arg1)
{
    qDebug() << Q_FUNC_INFO << arg1;

    if(0 == arg1) {
        if(m_pTimerLogin->isActive()) {
            m_pTimerLogin->stop();
        }
    }
}

/*
* Function:		slotRefreshUI
* Description:	The slot that refresh UI info
* Paramer:		void
* Return:		void
*/
void FormLogin::slotRefreshUI()
{
    qDebug() << Q_FUNC_INFO;

    // Fill the list of users into the combobox
    _loadUserList();

    // Fill the login option (rememer me & auto login)
    _loadLoginOption();

    if(ui->checkBox_AutoLogin->isChecked()) {
        m_pTimerLogin->start(DF_AUTO_LOGIN_TIMEOUT);
    }

    KeyboardMgr::getInstance()->setParent(this);
}

/*
* Function:		slotAutoLoginTimeout
* Description:	Auto login timeout
* Paramer:		void
* Return:		void
*/
void FormLogin::slotAutoLoginTimeout()
{
    qDebug() << Q_FUNC_INFO;

    m_pTimerLogin->stop();

    this->on_pushButton_Login_clicked();
}

/*
* Function:		_loadUserList
* Description:	Fill the list of users into the combobox
* Paramer:		void
* Return:		void
*/
void FormLogin::_loadUserList()
{
    qDebug() << Q_FUNC_INFO;

    // Clear all items
    ui->comboBox_User->clear();

    // Get the user list
    QList<QString> lstUsers;
//    BLL::DatabaseMgr::getInstance(this)->SelectUserList(lstUsers);
    lstUsers << DEF_ACCOUNT_FACTORY << DEF_ACCOUNT_ADMIN << DEF_ACCOUNT_GUEST;

    for(int i=lstUsers.size()-1; i>=0; i--) {
        ui->comboBox_User->addItem(lstUsers.at(i));
    }
}

/*
* Function:		_loadLoginOption
* Description:	Load login option info
* Paramer:		QString sUserName - the default user name
* Return:		void
*/
void FormLogin::_loadLoginOption(QString sUserName)
{
    qDebug() << Q_FUNC_INFO << sUserName;

    // Load the login info
    ST_CFG_LOGIN_INFO stLoginInfo;
    ConfigureBLL::getInstance(this)->loadLoginInfo(stLoginInfo);

    ui->comboBox_User->currentText().trimmed() = stLoginInfo.sLastUser;
    ui->checkBox_RememberMe->setChecked(stLoginInfo.bRememberPwd);
    ui->checkBox_AutoLogin->setChecked(stLoginInfo.bAutoLogin);

    if(sUserName.isEmpty()) {
        ui->comboBox_User->setCurrentText(stLoginInfo.sLastUser);
    }
    else {
        ui->comboBox_User->setCurrentText(sUserName);
    }

    ui->checkBox_RememberMe->setChecked(stLoginInfo.bRememberPwd);
    ui->checkBox_AutoLogin->setChecked(stLoginInfo.bAutoLogin);

    if(stLoginInfo.bRememberPwd && !stLoginInfo.sLastUser.isEmpty()) {
        QString sPwdAesUi = "";
        QString sPwdAesDb = "";

        DatabaseBLL_T1C::getInstance(this)->selectUserPwd(stLoginInfo.sLastUser, sPwdAesDb);
        sPwdAesUi = AlgorithmBLL_T1C::getInstance(this)->decryptionAES(sPwdAesDb);

        m_pLineEditPwd->setText(sPwdAesUi);
    }
    else {
        ui->checkBox_AutoLogin->setChecked(false);
        ui->checkBox_AutoLogin->setDisabled(true);
    }
}

/*
* Function:		_saveLoginOption
* Description:	Save login option info
* Paramer:		void
* Return:		void
*/
void FormLogin::_saveLoginOption()
{
    qDebug() << Q_FUNC_INFO;

    ST_CFG_LOGIN_INFO stLoginInfo;
    stLoginInfo.sLastUser = ui->comboBox_User->currentText().trimmed();
    stLoginInfo.bRememberPwd = ui->checkBox_RememberMe->isChecked();
    stLoginInfo.bAutoLogin = ui->checkBox_AutoLogin->isChecked();

    ConfigureBLL::getInstance(this)->saveLoginInfo(stLoginInfo);

    // Set the login mode
    ST_CFG_LOGIN_MODE stLoginMode;
    if(DEF_ACCOUNT_ADMIN == stLoginInfo.sLastUser) {
        stLoginMode.eumLoginMode = EUM_LOGIN_MODE::E_MODE_ADMIN;
    }
    else if(DEF_ACCOUNT_FACTORY == stLoginInfo.sLastUser) {
        stLoginMode.eumLoginMode = EUM_LOGIN_MODE::E_MODE_FACTORY;
    }
    else {
        stLoginMode.eumLoginMode = EUM_LOGIN_MODE::E_MODE_GUEST;
    }

    ConfigureBLL::getInstance(this)->saveLoginMode(stLoginMode);

    // Emit an signal that refresh login mode on the status bar
    emit signalRefreshLoginMode(stLoginMode.eumLoginMode);
}
